package com.tepth.appmanageservice.communicate;

import android.util.Log;

import com.tepth.appmanageservice.communicate.interfaces.IInterthreaded;
import com.tepth.appmanageservice.controllers.Client;
import com.tepth.appmanageservice.enums.EnumEvent;
import com.tepth.appmanageservice.interfaces.IAction;
import com.tepth.appmanageservice.protocol.Controller;
import com.tepth.appmanageservice.protocol.packets.Packets;
import com.tepth.appmanageservice.tools.LogTool;
import com.tepth.appmanageservice.tools.ext.ExtPro;
import com.tepth.appmanageservice.tools.ext.ExtToBytes;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

class Interthreaded implements IInterthreaded {
	private Socket socket;
	private DataOutputStream out = null;
	Boolean isLogin = false;
	private Client client;

	Client getClient() {
		return client;
	}

	Interthreaded() {
		client = new Client(this);
		ExtPro.setClient(client);
		Controller.setProtocolEvent(client);
	}

	void setSocket(Socket socket) {
		this.out = null;
		this.socket = socket;
	}

	public void send(Packets data) throws IOException {
		LogTool.i("发送", data);

		if (this.socket != null && this.out == null && !this.socket.isClosed() && this.socket.isConnected()) {
			this.out = new DataOutputStream(this.socket.getOutputStream());
		}

		if (this.out != null && this.socket != null && !this.socket.isClosed() && this.socket.isConnected()) {
			byte[] dataBytes = ExtPro.encryption(data.toBytes());
			this.out.write(dataBytes);
			LogTool.sendSuccess(dataBytes);
		}
	}

	private int BUFFER_SIZE = 1024;

	private void readRecursive(DataInputStream input, List<Byte> dataList) {
		byte[] buffer = new byte[this.BUFFER_SIZE];
		try {
			int revCount = input.read(buffer);
			for (int i = 0; i < revCount; i++) {
				dataList.add(buffer[i]);
			}

			if (revCount >= this.BUFFER_SIZE) {
				readRecursive(input, dataList);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private List<Byte> listByte = new ArrayList<>();

	private void readListener() throws Exception {
		byte[] buffer = new byte[this.BUFFER_SIZE];
		int revCount = 0;
		try {
			revCount = this.input.read(buffer);
		} catch (IOException e) {
			e.printStackTrace();
		}
		if (revCount == 0)
			return;
		if (revCount == -1)
			throw new Exception("");
		byte[] data;
		if (revCount <= this.BUFFER_SIZE) {
			int listByteSize = this.listByte.size();
			int x = 0;
			int dataLength;
			if (listByteSize > 0) {
				dataLength = revCount + listByteSize;
				data = new byte[dataLength];
				for (int i = 0; i < listByteSize; i++) {
					data[i] = this.listByte.get(i);
				}
				this.listByte.clear();
				x = listByteSize;
			} else {
				dataLength = revCount;
				data = new byte[revCount];
			}

			for (int i = 0; x < dataLength; x++) {
				data[x] = buffer[i++];
			}
		} else {
			List<Byte> dataList = new ArrayList<>();
			int listByteSize = this.listByte.size();
			if (listByteSize > 0) {
				for (int i = 0; i < listByteSize; i++) {
					dataList.add(this.listByte.get(i));
				}
			}
			for (int i = 0; i < revCount; i++) {
				dataList.add(buffer[i]);
			}

			this.readRecursive(this.input, dataList);
			int length = dataList.size();
			data = new byte[length];
			for (int i = 0; i < length; i++) {
				data[i] = dataList.get(i);
			}
		}
		this.revDataPretreatment(data);
	}

	private DataInputStream input;
	private IAction<EnumEvent> onSocketOffEvent;

	void listener() throws Exception {
		try {
			this.input = new DataInputStream(this.socket.getInputStream());
		} catch (IOException e) {
			e.printStackTrace();
		}

		try {
			while (true) {
				readListener();
			}
		} catch (Exception e) {
			Log.i("readListener", "失败");
			if (this.onSocketOffEvent != null) {
				this.onSocketOffEvent.Invoke(EnumEvent.SocketOffEvent);
			}
			throw e;
		}
	}

	private void revDataPretreatment(byte[] data) {
		LogTool.received(data);
		int i = data.length - 1;
		for (; i >= 0; i--) {
			if (i > 0) {
				if (data[i] == 0x7E && data[i - 1] == 0x7E) {
					break;
				}
			} else {
				if (data[i] != 0x7E) {
					break;
				}
			}
		}

		if (i != -1) {
			int index = i;
			for (; i < data.length; i++)
				this.listByte.add(data[i]);
			byte[] resdata = new byte[index];
			System.arraycopy(data, 0, resdata, 0, index);

			resultData(resdata);
		} else {
			resultData(data);
		}
	}

	private void resultData(byte[] data) {
		List<byte[]> dataList = subcontractor(data);
		int length = dataList.size();
		for (int i = 0; i < length; i++) {
			byte[] d = dataList.get(i);

			try {
				Controller.protocol(d);
			} catch (Exception ignored) {

			}
		}
	}

	private static List<byte[]> subcontractor(byte[] data) {
		List<byte[]> newDatas = new ArrayList<>();
		Boolean bengin = true;
		List<Byte> newData = new ArrayList<>();

		for (int i = 0; i < data.length; i++) {
			if (data[i] == 0x7E) {
				newData.add(data[i]);
				if (bengin)
					bengin = false;
				else {
					bengin = true;
					newDatas.add(ExtToBytes.fromByteList(newData));
					newData = new ArrayList<>();
				}
				continue;
			}

			if (data[i] == 0x7D) {
				byte d = data[i + 1];
				if (d == 0x02) {
					newData.add((byte) 0x7E);
					i++;
					continue;
				} else if (d == 0x01) {
					newData.add((byte) 0x7D);
					i++;
					continue;
				}
			}
			newData.add(data[i]);
		}
		return newDatas;
	}

	void setOnSocketOffEvent(IAction<EnumEvent> action) {
		this.onSocketOffEvent = action;
	}

	void setOnAESReplyEvent(IAction<EnumEvent> action) {
		this.client.setOnAESReplyEvent(action);
	}

	@Override
	public void setLogin(Boolean bool) {
		this.isLogin = bool;
	}
}